#[macro_export]
macro_rules! map {
    (@unit $($x:tt)*) => {
        (())
    };
    (@count $($rest:expr),*) => {
        (<[()]>::len(&[$(map!(@unit $rest)),*]))
    };
    ($($key:expr => $value:expr),* $(,)*) => {{
        let cap = ((map!(@count $($key),*) as f32/0.7)+0.5) as usize;
        let mut _map = std::collections::HashMap::with_capacity(cap);
        $(_map.insert(String::from($key), $value);)*
        _map
   }};
}

#[macro_export]
macro_rules! render {
    ($path:expr) => {{
        let mut ctx = tera::Context::new();
        ctx.insert("ctx", &crate::CONTEXT_PATH);
        let body = crate::util::G_TPL.clone().render($path, &ctx).unwrap();
        
        actix_web::HttpResponse::Ok()
            .content_type("text/html; charset=utf-8")
            .body(body)
    }};
    ($path:expr, &$data:expr) => {{
        let body = crate::util::G_TPL.clone().render($path, &$data).unwrap();
        
        actix_web::HttpResponse::Ok()
            .content_type("text/html; charset=utf-8")
            .body(body)
    }};
}

#[derive(Debug)]
#[derive(Clone)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Vo {
    #[serde(flatten)]
    pub data: std::collections::HashMap<String, String>
}
impl Vo {
    #[inline(always)]
    pub fn len(&self) -> usize {
        self.data.len()
    }
    #[inline(always)]
    pub fn empty(&self) -> bool {
        self.data.is_empty()
    }
    #[inline(always)]
    pub fn some(&self, key: &str) -> bool {
        self.data.get(key).is_some()
    }
    #[inline(always)]
    pub fn blank(&self, key: &str) -> bool {
        if let Some(val) = self.data.get(key) {
            val.is_empty()
        } else {
            true
        }
    }
    #[inline(always)]
    pub fn not_blank(&self, key: &str) -> bool {
        !self.blank(key)
    }
    #[inline(always)]
    pub fn str(&self, key: &str) -> &str {
        self.data.get(key)
            .expect("获取str值失败")
            .as_str()
    }
    #[inline(always)]
    pub fn int(&self, key: &str) -> u16 {
        self.data.get(key)
            .expect("获取int值失败")
            .parse::<u16>()
            .expect("转换int值失败")
    }
    #[inline(always)]
    pub fn bool(&self, key: &str) -> bool {
        self.data.get(key)
            .expect("获取bool值失败")
            .parse::<bool>()
            .expect("转换bool值失败")
    }
    #[inline(always)]
    pub fn long(&self, key: &str) -> u32 {
        self.data.get(key)
            .expect("获取long值失败")
            .parse::<u32>()
            .expect("转换long值失败")
    }
    #[inline(always)]
    pub fn double(&self, key: &str) -> f64 {
        self.data.get(key)
            .expect("获取double值失败")
            .parse::<f64>()
            .expect("转换double值失败")
    }
}
